package ylzy.com.yanglezhiyang;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;

import tyrantgit.explosionfield.ExplosionAnimator;

public class GameView extends View {

    final String TAG = "GameView";

    public Paint paint = new Paint();
    public boolean isInit = false;
    public ArrayList<Floor> floors = new ArrayList<>();
    public ArrayList<GameObject> sb = new ArrayList<>();
    public boolean isAddAninEnd = true;
    public Queue<GameObject> queueToAdd = new LinkedList<>();
    public boolean isGameOver = false;
    public boolean isGameSuccess = false;
    public Bitmap bmpKuang;//纹理
    public Bitmap bmpFailed;//纹理
    public Bitmap bmpSuccess;//纹理
    public Bitmap bg;//纹理
    public Rect[] srcRects = new Rect[7];
    public Rect[] dstRects = new Rect[7];
    public Rect bgSrcRect = new Rect();
    public Rect bgDstRect = new Rect();

    public GameView(Context context) {
        super(context);
    }

    public GameView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public GameView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public GameView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (!isInit) {
            isInit = true;
            floors = LevelUtil.getLevel2();
            bmpKuang = BitmapFactory.decodeResource(getContext().getResources(), R.mipmap.kuang);
            bmpFailed = BitmapFactory.decodeResource(getContext().getResources(), R.mipmap.failed);
            bmpSuccess = BitmapFactory.decodeResource(getContext().getResources(), R.mipmap.success);
            bg = BitmapFactory.decodeResource(getContext().getResources(), R.mipmap.bg);

            int w = getWidth() / 9;
            for (int i = 0; i < 7; i++) {
                srcRects[i] = new Rect(0,0,bmpKuang.getWidth(),bmpKuang.getHeight());
                dstRects[i] = new Rect(w * (i + 1), getHeight() - w, w * (i + 2),  getHeight());
            }
            bgSrcRect = new Rect(0,0, bg.getWidth(), bg.getHeight());
            bgDstRect = new Rect(0,0, getWidth(), getHeight());

        }

        drawBg(canvas, paint);
        drawSpit(canvas, paint);
        drawBottom(canvas, paint);

        if (isGameOver) {
            showGameOver(canvas, paint);
        }

        if (isGameSuccess) {
            showGameSuccess(canvas, paint);
        }

        for (ExplosionAnimator explosion : mExplosions) {
            explosion.draw(canvas);
        }

    }

    private List<ExplosionAnimator> mExplosions = new ArrayList<>();
    public boolean isExplosionAninEnd = true;

    public void explosion(GameObject d){
        final ExplosionAnimator explosion = new ExplosionAnimator(this, d.bmp, d.dst);
        explosion.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                mExplosions.remove(animation);
                if(mExplosions.size()==0){
                    isExplosionAninEnd = true;
                }
            }
        });
        explosion.setStartDelay(0);
        explosion.setDuration(200);
        mExplosions.add(explosion);
        explosion.start();
        isExplosionAninEnd = false;
    }

    public void drawSpit(Canvas canvas, Paint paint) {
        for (int i = 0; i < floors.size(); i++) {
            Floor floor = floors.get(i);
            if(floor.isStack){
                for (int j=0;j<floor.spirits.size();j++) {
                    if (j==floor.spirits.size()-1) {
                        floor.spirits.get(j).setState(1);
                    } else {
                        floor.spirits.get(j).setState(-1);
                    }
                }
            }else{
                if(i==floors.size()-1){
                    for (GameObject gameObject : floors.get(floors.size() - 1).spirits) {
                        gameObject.setState(1);
                    }
                    continue;
                }
                for (GameObject gameObject : floor.spirits) {
                    if (gameObject.state == 1) {
                        continue;
                    }
                    boolean isCovered = false;
                    for (int j = i + 1; j < floors.size(); j++) {
                        for (GameObject temp : floors.get(j).spirits) {
                            if (gameObject.isCovered(temp)) {
                                isCovered = true;
                                break;
                            }
                        }
                        if (isCovered) {
                            break;
                        }
                    }
                    if (isCovered) {
                        gameObject.setState(0);
                    } else {
                        gameObject.setState(1);
                    }

                }
            }
        }

        for (Floor floor : floors) {
            floor.draw(canvas, paint);
        }
    }

    public void drawBottom(Canvas canvas, Paint paint) {
        int w = getWidth() / 9;
        for (int i = 0; i < 7; i++) {
            canvas.drawBitmap(bmpKuang, srcRects[i], dstRects[i], paint);
        }

        for (GameObject g : sb) {
            g.draw(canvas, paint);
        }
    }

    public void drawBg(Canvas canvas, Paint paint) {
        canvas.drawBitmap(bg, bgSrcRect, bgDstRect, paint);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (isGameOver) {
            return true;
        }

        if (sb.size() + queueToAdd.size() >= 7) {
            return true;
        }

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                boolean isCovered = false;
                GameObject top = null;
                for (int i = 0; i < floors.size(); i++) {
                    Floor floor = floors.get(i);
                    for (GameObject gameObject : floor.spirits) {
                        if (gameObject.state == 1) {
                            if (gameObject.isCovered((int) event.getX(), (int) event.getY())) {
                                top = gameObject;
                                isCovered = true;
                                break;
                            }
                        }
                    }
                    if (isCovered) {
                        break;
                    }
                }

                if (top != null && top.floor != null && top.isCovered((int) event.getX(), (int) event.getY())) {
                    top.floor.remove(top);
                    queueToAdd.add(top);
                    SoundPoolUtils.play(SoundPoolUtils.SOUND_CLICK);
                    VibratorUtil.vibrate();
                    if (isAddAninEnd) {
                        GameObject temp = queueToAdd.poll();
                        if(temp!=null){
                            moveToGroove(temp);
                        }
                    }
                    top = null;
                } else {
                    top = null;
                }

                break;
            case MotionEvent.ACTION_UP:
                break;
        }

        postInvalidate();
        return true;
    }

    AninEndListner aninMoveEndListner = new AninEndListner() {

        @Override
        public void end() {

        }
    };

    AninEndListner aninAddEndListner = new AninEndListner() {
        @Override
        public void end() {
            isAddAninEnd = true;

            int sameCount = 0;
            int startIndex = 0;
            int lastCat = 0;
            for (int i = 0; i < sb.size(); i++) {
                GameObject g = sb.get(i);
                if (lastCat == g.category) {
                    sameCount++;
                } else {
                    sameCount = 0;
                    lastCat = g.category;
                    startIndex = i;
                    sameCount++;
                }
                if (sameCount == 3) {
                    break;
                }
            }

            if (sameCount == 3) {
                GameObject g0 = sb.get(startIndex);
                GameObject g1 = sb.get(startIndex+1);
                GameObject g2 = sb.get(startIndex+2);

                explosion(g0);
                explosion(g1);
                explosion(g2);

                sb.remove(g0);
                sb.remove(g1);
                sb.remove(g2);

                for (int i = startIndex; i < sb.size(); i++) {
                    GameObject g = sb.get(i);
                    g.moveToDst(GameView.this, g.x - g.w * 3, g.y, aninMoveEndListner,0,100);
                }

                SoundPoolUtils.play(SoundPoolUtils.SOUND_DISMISS);
            }

            if (sb.size() >= 7) {
                isGameOver = true;
                postInvalidate();
                SoundPoolUtils.play(SoundPoolUtils.SOUND_FAILED);
            }

            int count = 0;
            for(Floor f : floors){
                for(GameObject g : f.spirits){
                    count++;
                    break;
                }
                if(count>0){
                    break;
                }
            }
            if(count==0){
                isGameSuccess = true;
                postInvalidate();
                SoundPoolUtils.play(SoundPoolUtils.SOUND_SUCCESS);
            }

            GameObject temp = queueToAdd.poll();
            if(temp!=null){
                moveToGroove(temp);
            }

        }
    };


    public void moveToGroove(GameObject top) {
        int w = getWidth() / 9 * (sb.size() + 1);
        int index = sb.size();
        boolean isHaveSame = false;
        for (int i = sb.size() - 1; i >= 0; i--) {
            if (sb.get(i).category == top.category) {
                w = getWidth() / 9 * (i + 2);
                index = i;
                isHaveSame = true;
                break;
            }
        }

        if (!isHaveSame) {
            int h = getWidth() / 9;
            sb.add(top);
            top.moveToDst(this, w, getHeight() - h, aninAddEndListner,0,250);

        } else {
            int h = getWidth() / 9;
            sb.add(index + 1, top);
            top.moveToDst(this, w, getHeight() - h, aninAddEndListner, 100,250);

            for (int i = index + 2; i < sb.size(); i++) {
                GameObject g = sb.get(i);
                g.moveToDst(this, g.x+g.w, g.y, null,0,100);
            }

        }

        top = null;
        isAddAninEnd = false;
    }

    public void showGameOver(Canvas canvas, Paint paint) {

        canvas.drawColor(0X80000000);

        int x = (getWidth() - bmpFailed.getWidth()*2)/2;
        int y = (getHeight() - bmpFailed.getHeight()*2)/2;

        Rect src = new Rect(0,0,bmpFailed.getWidth(),bmpFailed.getHeight());
        Rect dst = new Rect(x, y, x+bmpFailed.getWidth()*2,  y+bmpFailed.getHeight()*2);

        canvas.drawBitmap(bmpFailed, src, dst, paint);
    }

    public void showGameSuccess(Canvas canvas, Paint paint) {

        canvas.drawColor(0X80000000);

        int x = (getWidth() - bmpSuccess.getWidth()*2)/2;
        int y = (getHeight() - bmpSuccess.getHeight()*2)/2;

        Rect src = new Rect(0,0,bmpSuccess.getWidth(),bmpSuccess.getHeight());
        Rect dst = new Rect(x, y, x+bmpSuccess.getWidth()*2,  y+bmpSuccess.getHeight()*2);

        canvas.drawBitmap(bmpSuccess, src, dst, paint);


    }
}
